Rendering and displaying three dimensional (3-D) graphics on screen typically involves many calculations and computations. In a simple graphics system, such computations occur according to some level of cooperative or shared processing by the central processing unit (CPU) and the graphics processing unit (GPU). In an exemplary scenario, after instructions are processed and some initial computations occur in the CPU, a set of coordinate points or vertices that define the object to be rendered are stored in video memory for further processing by the GPU in the graphics pipeline. When graphics programmers develop graphics applications via a set of available graphics APIs, the programmer generally indicates a set of vertices to be operated upon by a set of algorithmic elements. This data is sent into the graphics pipeline, and each vertex is streamed through a fixed set of GPU subunits in the graphics pipeline. One or more programmable shader units, sometimes referred to as shaders or “shader programs,” can operate on the data and perform specialized operations on graphics data. As used herein, the term “shader” can be used to generically to refer to either the hardware subunit of the GPU that performs the shading or to refer to the set of instructions or tokens downloaded to the GPU that are subsequently loaded into memory, e.g., register storage, used by the shader (hardware) to perform the shading. The term “shader” can also refer to both working together. Where the term “subunit” is also used in connection with the term “shader,” the term “shader” should be construed to refer to the subunit of the GPU that performs the processing associated with the shading. The term “shader program” can generally refer to computer programs or processes, that reside and run in the graphics pipeline, which can be used to help determine/define the final, on-screen surface properties of an image or object in a 3D on-screen environment. “Shaders” can perform billions of computations a second in order to perform their specific tasks. Shaders can include, for example, vertex shader(s), geometry shader(s) and pixel shader(s).
A single shader can receive different combinations of “shader constants.” As used herein, the term “shader constant” can refer to different parameters or variables that are fed into a shader program that allow the shader program to produce different results based on the particular shader constants that are used. Shader programs can receive a range of different values for each shader constant. Shader constant variables to not change values during the invocation of that shader. Depending on the combination of particular shader constants that are provided, the output generated by the shader will vary. These shader constants can specify, for example, how pixels are combined, how data is read in and out, and in the case of a texture, how values are extracted from that texture. The process of shading is a computation intensive and complex process. When these specific shaders operate in a graphics pipeline, there are regular bottlenecks due to the operations that occur in each stage.
“State” refers to resources being interpreted by the shader program. As used herein, the term “resources” can refer to inputs used by a shader program and can encompass, for example, textures, samplers, constant buffers, or any other resource used by shader programs. At any given instance, the graphics pipeline contains a tremendous amount of dynamic state (rendering state, shaders, shader constant variables, resource/memory bindings, etc.). Different combinations of state enable various simulated materials and visual effects. One component of this state is a set of shader constants that need to be bound to the GPU before executing a shader program.
In the effects system, there are a number of effects that are being rendered by the graphics pipeline of the GPU. Because the hardware used to implement the graphics pipeline can be in only one configuration at any given instance, it is desirable to reduce time spent setting state (e.g., shader constants) and issuing commands to the GPU. The number of unique materials and effects that can be rendered in a frame is dictated by the performance of this system. In the process of rendering the GPU will consume variables and generate values used to produce various effects. The representation of each variables sent to the GPU can vary.
FIG. 1 is a flow chart showing a conventional handle-based technique 105 for setting a value to an effect variable in a state management system of a conventional effects system.
At step 110, when an effect variable (e.g., 5.5 f) is requested by an application at load time, a method (e.g., GetVariableByName) on the effect variable returns a handle (e.g., a number or other unique identifier) that points to the effect variable at step 120. This effect variable corresponds to a piece of device state that that is stored in memory, but that can not be used by the application. It should be appreciated that if a handle is requested that is not specified in the effects system, when the set method is called then the effects system may crash since it tries to operate on a null pointer.
Each of the variables must be “set” to a value by the application to achieve the desired effects. Before the application can set a value to the effect variable, the state management system of the GPU performs validation on the effect variable at run-time (step 130). Performing validation each time a value is set helps ensure that the value is represented in the correct form when the run-time engine calls the function. Validation involves a series of “checks” to make sure that the input and the output data types and alignments match up, that the caller has permissions to access the requested data, etc. In a handle based system such as that described in FIG. 1, only “slow paths” are provided. In other words, upon getting a handle, the state management system performs an internal lookup in a table to determine what the handle is pointing to, a type check to determine what type of variable the handle is referring to (e.g., if the variable type matches the variable type that is being passed in), a determination as to whether a transformation or conversion is necessary before setting the value, etc. The state management system of the GPU can therefore determine what the GPU is expecting, what variable type is being provided, whether a conversion/transpose is needed (i.e., is the variable type being passed in a type that is allowed, etc.). If input and output types do not match, some scenarios may call for a data conversion to occur. In other cases an error is returned. For instance, if the value that the GPU hardware will consume is expected to be specified as an integer, but the variable happens to be stored is a floating-point value, or vice-versa, the data types do not match up. As such, a conversion needs to be performed to convert the variable from the effects file to a floating point variable before a value can be set to the object. This can be referred to as a “slow path” for setting a value to the effect since a conversion will first be performed before the set can take place.
Once the effect variable has been validated the application knows how the effect variable is to be used. If a conversion is needed, the effect variable can then be modified by the application at step 140, and a value can be set as part of an effect by the state management system of the effects system at step 150. The value can be set, for example, using a generic SetValue method (pVar−>SetValue(5.5 f)), where pVar is a generic variable pointer to the effect variable which tells the effects system to update the value of the effect variable.